#include <stdio.h>
#include <curl/curl.h>
#include "evue_curl.h"


#define ACCEPT "Accept: application/json"
#define CONTENT_TYPE "Content-Type: application/json"
#define CHARSET "charsets: utf-8"


int curl_evm(evm_t* e, evm_val_t * request, write_cb_t cb, void *chunk, write_cb_t header_cb, void *headermsg)
{
    evm_val_t *eurl = evm_prop_get(e, request, "url", 0);
    evm_val_t *emethod = evm_prop_get(e, request, "method", 0);
    evm_val_t *epostfield = evm_prop_get(e, request, "data", 0);
    evm_val_t *eheaders = evm_prop_get(e, request, "headers", 0);
    evm_val_t *etimeout = evm_prop_get(e, request, "timeout", 0);

    const char *url = NULL;
    if (!eurl){
        return -1;
    }
    if (eurl && evm_is_string(eurl)){
        url = evm_2_string(eurl);
    }

    const char *method = NULL;
    if (emethod && evm_is_string(emethod)){
        method = evm_2_string(emethod);
    }

    const char *postfield = NULL;
    if (epostfield && evm_is_string(epostfield)){
        postfield = evm_2_string(epostfield);
    }else if (epostfield && evm_is_buffer(epostfield)){
        postfield = evm_buffer_addr(epostfield);
    }

    struct curl_slist *headers = NULL;
    if (eheaders && evm_is_list(eheaders) && evm_list_len(eheaders) > 0){
        uint32_t len = evm_list_len(eheaders);
        for(uint8_t i = 0; i < len ; i++){
            evm_val_t * item = evm_list_get(e, eheaders, i );
            if (evm_is_string(item)){
                const char * header = evm_2_string(item);
                headers = curl_slist_append(headers, header);
            }
        }
    }else if (eheaders && evm_is_string(eheaders)){
        const char * header = evm_2_string(eheaders);
        headers = curl_slist_append(headers, header);
    }else{
        headers = curl_slist_append(headers, ACCEPT);
        headers = curl_slist_append(headers, CONTENT_TYPE);
        headers = curl_slist_append(headers, CHARSET);
    }



    CURL *curl;
    CURLcode res = CURLE_OK;
    long http_code = 0;

//    curl_global_init(CURL_GLOBAL_DEFAULT);

    curl = curl_easy_init();
    if(curl) {
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
        curl_easy_setopt(curl, CURLOPT_URL, url);
        if (!strcmp(method, "POST") && postfield){
            curl_easy_setopt(curl, CURLOPT_POSTFIELDS,postfield);

            if (epostfield && evm_is_buffer(epostfield)){
                uint32_t buffer_len = evm_buffer_len(epostfield);
                curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE,buffer_len);
            }
        }
        if(!strcmp(method,"POST"))
            curl_easy_setopt(curl, CURLOPT_POST, 1);
        if(!strcmp(method,"PUT"))
            curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");

        if (etimeout && evm_is_number(etimeout)){
            int32_t timeout = evm_2_integer(etimeout);
            curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout);
        }

        curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);

        /* send all data to this function  */
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, cb);

        curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_cb);
        curl_easy_setopt(curl, CURLOPT_HEADERDATA, headermsg);

        /* we pass our 'chunk' struct to the callback function */
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, chunk);

        /* some servers don't like requests that are made without a user-agent
        field, so we provide one */
        curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0");

        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);

        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);

        curl_easy_setopt(curl, CURLOPT_BUFFERSIZE, 1024 * 1024 * 1024L);
        /* Perform the request, res will get the return code */
        res = curl_easy_perform(curl);

        curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
        printf("HTTP_CODE: %ld\n\n", http_code);

        /* Check for errors */
        if(res != CURLE_OK){
            fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
        }
        /* always cleanup */
        curl_slist_free_all(headers);
        curl_easy_cleanup(curl);
    }

//    curl_global_cleanup();
    if(http_code < 200 ){
        http_code = res;
    }

    return http_code;
}




int curl_raw(const char *url, const char *method, const char *postfield, struct curl_slist *headers, write_cb_t cb, void *chunk)
{
    CURL *curl;
    CURLcode res = CURLE_OK;
    long http_code = 0;

//    curl_global_init(CURL_GLOBAL_DEFAULT);

    curl = curl_easy_init();
    if(curl) {
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
        curl_easy_setopt(curl, CURLOPT_URL, url);
        if (!strcmp(method, "POST") && postfield){
            curl_easy_setopt(curl, CURLOPT_POSTFIELDS,postfield);
        }
        if(!strcmp(method,"POST"))
            curl_easy_setopt(curl, CURLOPT_POST, 1);
        if(!strcmp(method,"PUT"))
            curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");

        /* send all data to this function  */
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, cb);

        /* we pass our 'chunk' struct to the callback function */
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, chunk);

        /* some servers don't like requests that are made without a user-agent
        field, so we provide one */
        curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0");

        /* Perform the request, res will get the return code */
        res = curl_easy_perform(curl);

        curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
        printf("HTTP_CODE: %ld\n\n", http_code);

        /* Check for errors */
        if(res != CURLE_OK){
            fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
        }
        /* always cleanup */
        curl_slist_free_all(headers);
        curl_easy_cleanup(curl);
    }

//    curl_global_cleanup();

    return res;
}

int curl(const char *url, const char *method, const char *postfield, const char *header, write_cb_t cb, void * chunk){


    struct curl_slist *headers=NULL;
    headers = curl_slist_append(headers, ACCEPT);
    headers = curl_slist_append(headers, CONTENT_TYPE);
    headers = curl_slist_append(headers, CHARSET);
    if(header && *header != '\0'){
        headers = curl_slist_append(headers, header);
    }
    return curl_raw(url, method, postfield, headers, cb, chunk);
}
